﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace AramaruForest
{
    class Sprite
    {
        public PointF Velocity;
        public PointF Acceleration;
        public PointF Location;
        public PointF OldLocation;
        public PointF DrawLocation;
        public SizeF Size;
        public PointF OldVelocity;
        public bool Flip;
        public bool Hero;
        public bool DownFlip;
        public int hp;
        public int heals;
        public bool attackingUp;
        public bool attackingClose;
        public string message;
        public string trap;
        public int trapCycler;
        public bool projectile;
        public bool groundSurvives;
        public int attack;
        public bool gravity;
        public bool thrown;
        public int attackCycler = 50;
        public int CurrentFrame;
        public bool win;
        public bool loose;
        private Color _colorKey;
        private ImageAttributes _attributes;
        protected List<Bitmap> _frames = new List<Bitmap>();
        private List<Rectangle> _rectangle = new List<Rectangle>();
        public Dictionary<string, Bitmap> OtherFrames = new Dictionary<string, Bitmap>();
        public int AttackTime;
        protected GameState _gameState;
        public bool Airborn;
        public bool Collider;
        public int AI;
        public bool HeroItem;
        public int _kunai;

        public double JumpTime;
        public double JumpStart;
        public double JumpForce;

        public int Hp
        {
            get { return hp; }
            set {
                if (!thrown)
                {
                    hp = value;
                    if (hp < 0)
                        hp = 0;
                }
                }
        }

        public bool Thrown
        {
            get { return thrown; }
            set 
            { 
                thrown = value;
                
            }
        }

        public Sprite(GameState gameState, float x, float y, string filename)
        {
            // Load the bitmap
            _frames.Add(new Bitmap(filename));

            // Set the location and use the height and width from the 1st frame
            initialize(gameState, x, y, _frames[0].Width, _frames[0].Height);
        }

        public Sprite(GameState gameState, float x, float y, string filename1, string filename2)
        {
            // Load the 2 animation frames
            _frames.Add(new Bitmap(filename1));
            _frames.Add(new Bitmap(filename2));

            // Set the location and use the height and width from the 1st frame
            initialize(gameState, x, y, _frames[0].Width, _frames[0].Height);
        }

        public Sprite(GameState gameState, float x, float y, string filename, Rectangle rectangle, int numberAnimationFrames)
        {
            Bitmap bitmap = new Bitmap(filename);

            for (int i = 0; i < numberAnimationFrames; i++)
            {
                _frames.Add(bitmap);

                // Set the location and use the height and width from the 1st frame
                initialize(gameState, x, y, rectangle.Width / numberAnimationFrames, rectangle.Height);

                _rectangle.Add(new Rectangle(rectangle.X + i * rectangle.Width / numberAnimationFrames, rectangle.Y,
                                              rectangle.Width / numberAnimationFrames, rectangle.Height));
            }
        }

        private Sprite()
        {
            // No default constructor 
            // (it's private so nothing can call it, and must use a parameterized constructor)
        }

        public void Update(double gameTime, double elapsedTime)
        {
            ApplyPhysics(elapsedTime, gameTime);

            
            OldLocation = Location;
            // Move the sprite
            Location.X += Velocity.X * (float)elapsedTime;
            Location.Y += Velocity.Y * (float)elapsedTime;

            // Add in any acceleration
            Velocity.X += Math.Sign(Velocity.X) * Acceleration.X * (float)elapsedTime;
            Velocity.Y += Math.Sign(Velocity.Y) * Acceleration.Y * (float)elapsedTime;

            if (DownFlip && Velocity.Y >= 0)
                _frames[0] = new Bitmap(@"Data\Hero\KunaiDown.bmp");
            TerminalVelocity();
            
        }

        private void TerminalVelocity()
        {
            if (Velocity.X > 200)
                Velocity.X = 200;
            else if (Velocity.X < -200)
                Velocity.X = -200;
            if (Velocity.Y > 120)
                Velocity.Y = 120;
            else if (Velocity.Y < -200)
                Velocity.Y = -200;
        }

        public void Draw(Graphics graphics)
        {
            bool bAirborn = !OnGround();
            if (!Airborn && bAirborn)
                JumpTime = _gameState._world._gameTime;
            Airborn = bAirborn;

            if (AttackTime < 0)
                AttackTime++;
            if (AttackTime > 0)
            {
                AttackTime--;
                if (AttackTime == 0)
                {
                    attackingUp = false;
                    attackingClose = false;
                }
            }
            

            if (Location.X + Size.Width >= _gameState._world.WorldLimits.Width)
            {
                Location.X = _gameState._world.WorldLimits.Width - Size.Width - 1;
                Velocity.X = 0;
               
            }
            if (Location.X < 0)
            {
                Location.X = 0;
                Velocity.X = 0;
            }
            if (Location.Y + Size.Height > _gameState._world.WorldLimits.Height)
            {
                Location.Y = _gameState._world.WorldLimits.Height - Size.Height;
                Velocity.Y = 0;

            }
            if (Location.Y < 0)
            {
                Location.Y = 0;
                if(Velocity.Y < 0)
                    Velocity.Y = 0;
               
            }

            if(Location.X <= _gameState._world.CameraLocation.X - _gameState._world.Camera.Width && Location.X >= _gameState._world.CameraLocation.X)
                return;

            DrawLocation = Location;
            DrawLocation.X = Location.X - _gameState._world.CameraLocation.X;
            DrawLocation.Y = Location.Y - _gameState._world.CameraLocation.Y;

            // Draw the correct frame at the current point
            if (_rectangle[CurrentFrame] == Rectangle.Empty)
            {
                if (thrown)
                {
                    graphics.DrawImage(OtherFrames["Hurt"], DrawLocation.X, DrawLocation.Y, Size.Width, Size.Height);
                }
                
            }
            else
            {
                // Where to draw the sprite on the screen.
                Rectangle outputRect = Rectangle.Empty;

                if (Flip)
                {
                    outputRect = new Rectangle((int)DrawLocation.X + (int)Size.Width, (int)DrawLocation.Y, -(int)Size.Width, (int)Size.Height);
                }
                else
                {
                    outputRect = new Rectangle((int)DrawLocation.X, (int)DrawLocation.Y, (int)Size.Width, (int)Size.Height);
                }
                if(thrown)
                    
                {
                    if (_attributes == null)
                    {
                        graphics.DrawImage(OtherFrames["Hurt"], outputRect,
                                                                    _rectangle[CurrentFrame].X, _rectangle[CurrentFrame].Y,
                                                                    _rectangle[CurrentFrame].Width, _rectangle[CurrentFrame].Height,
                                                                    GraphicsUnit.Pixel);
                    }
                    else
                    {
                        graphics.DrawImage(OtherFrames["Hurt"], outputRect,
                                                                    _rectangle[CurrentFrame].X, _rectangle[CurrentFrame].Y,
                                                                    _rectangle[CurrentFrame].Width, _rectangle[CurrentFrame].Height,
                                                                    GraphicsUnit.Pixel, _attributes);
                    }
                    
                }
                else if (AttackTime <= 0)
                {
                    if (_attributes == null)
                    {
                        graphics.DrawImage(_frames[CurrentFrame], outputRect,
                                                                    _rectangle[CurrentFrame].X, _rectangle[CurrentFrame].Y,
                                                                    _rectangle[CurrentFrame].Width, _rectangle[CurrentFrame].Height,
                                                                    GraphicsUnit.Pixel);
                    }
                    else
                    {
                        graphics.DrawImage(_frames[CurrentFrame], outputRect,
                                                                    _rectangle[CurrentFrame].X, _rectangle[CurrentFrame].Y,
                                                                    _rectangle[CurrentFrame].Width, _rectangle[CurrentFrame].Height,
                                                                    GraphicsUnit.Pixel, _attributes);
                    }
                }
                else
                {
                    string frame = "Attack";
                    if (attackingUp)
                    {
                        frame = "Attack2";
                       
                    }
                    else if (attackingClose)
                    {
                        if (AttackTime >= 6)
                            frame = "Attack2";
                        else 
                            frame = "Attack";
                        
                    }

                    if (_attributes == null)
                    {
                        graphics.DrawImage(OtherFrames[frame], outputRect,
                                                                    _rectangle[CurrentFrame].X, _rectangle[CurrentFrame].Y,
                                                                    _rectangle[CurrentFrame].Width, _rectangle[CurrentFrame].Height,
                                                                    GraphicsUnit.Pixel);
                    }
                    else
                    {
                        graphics.DrawImage(OtherFrames[frame], outputRect,
                                                                    _rectangle[CurrentFrame].X, _rectangle[CurrentFrame].Y,
                                                                    _rectangle[CurrentFrame].Width, _rectangle[CurrentFrame].Height,
                                                                    GraphicsUnit.Pixel, _attributes);
                    }
                    
                }
            }
            
        }

        public Color ColorKey
        {
            get { return _colorKey; }
            set
            {
                _colorKey = value;

                if (_attributes != null)
                {
                    _attributes.Dispose();
                }

                // Set the color key for this sprite;
                _attributes = new ImageAttributes();
                _attributes.SetColorKey(_colorKey, _colorKey);
            }
        }

        public int NumberOfFrames
        {
            get { return _frames.Count; }
        }

        private void initialize(GameState gameState, float x, float y, float width, float height)
        {
            _gameState = gameState;
            Location.X = x;
            Location.Y = y;
            Size.Width = width;
            Size.Height = height;
            CurrentFrame = 0;
            Hp = 1;
            message = null;
        }

        public void ApplyPhysics(double elapsedTime, double gameTime)
        {
            if (gravity)
            {
                bool bAirborn = !OnGround();
                if (!Airborn && bAirborn)
                    JumpStart = gameTime;
                if (!Airborn && !bAirborn)
                {
                    JumpStart = gameTime;
                    JumpForce = 0;
                }

                Airborn = bAirborn;
                if (Airborn)
                {
                    JumpTime = gameTime - JumpStart;
                    Velocity.Y = 188 * (float)JumpTime - (float)JumpForce;
                
                    if (Velocity.Y == 0)
                        Velocity.Y = 1;
                }
                else
                {
                    if(Velocity.Y > 0)
                    Velocity.Y = 0;
                    
                }
                
                
            }
            if (Velocity.Y == 0 && Thrown)
            {
                Thrown = false;
                Velocity.X = 0;
            }

            Airborn = !OnGround();
        }

        public static bool Collision(Sprite sprite1, Sprite sprite2)
        {
           

                // See if the sprite rectangles overlap
                return !(sprite1.Location.X >= sprite2.Location.X + sprite2.Size.Width
                        || sprite1.Location.X + sprite1.Size.Width <= sprite2.Location.X
                        || sprite1.Location.Y > sprite2.Location.Y + sprite2.Size.Height
                        || sprite1.Location.Y + sprite1.Size.Height < sprite2.Location.Y);
            
            
        }

       
        public bool OnGround()
        {
            bool l = false; 
            foreach (Sprite tile in _gameState._world._gameItems.Area)
            {
                if (AI == 5 && Sprite.Collision(tile, this))
                    hp = 0;
                if ((tile.trap == "falling" && trap == "falling"))
                    continue;
                //land on the sprite
                if ( tile.Collider  && (Collide(tile) || ((int)Location.Y == (int)tile.Location.Y - (int)Size.Height - 1 && ((Location.X + Size.Width >= tile.Location.X && Location.X + Size.Width <= tile.Location.X + tile.Size.Width) || (Location.X >= tile.Location.X && Location.X <= tile.Location.X + tile.Size.Width)))))
                {
                    l = true;
                    JumpForce = 0;
                    JumpStart = _gameState._world._gameTime;

                    if (tile.trap == "block" && this.Hero)
                    {
                        tile.gravity = true;
                        tile.JumpStart = _gameState._world._gameTime;
                        tile.Airborn = true;
                        tile.Velocity.Y = 1;
                        tile.trap = "falling";
                    }
                    
                }  
            }
            if (Location.Y + Size.Height >= _gameState._world.WorldLimits.Height)
                l = true;

            return l;
        }

        public bool OnGround(Sprite i)
        {
            bool l = false;
            
                //land on the sprite
                if (i.Collider && (Collide(i) || ((int)Location.Y == (int)i.Location.Y - (int)Size.Height - 1 && ((Location.X + Size.Width >= i.Location.X && Location.X + Size.Width <= i.Location.X + i.Size.Width) || (Location.X >= i.Location.X && Location.X <= i.Location.X + i.Size.Width)))))
                {
                    l = true;
                    JumpForce = 0;
                    JumpStart = _gameState._world._gameTime;

                }
            
            

            return l;
        }


        public bool Collide(Sprite i)
        {

            if (Sprite.Collision(this, i) && i.Collider)
            {
                
                if (Velocity.X != 0 && Velocity.Y != 0)
                {
                   
                    PointF sl = Location;
                    float v = Velocity.X;
                    Location.X = OldLocation.X;
                    //Velocity.X = 0;
                    if (!Sprite.Collision(i, this))
                    {
                        return false;
                        
                    }
                    else
                    {
                        Location = sl;
                        Velocity.X = v;
                    }
                }

                if (Velocity.Y != 0)
                {
                    float saveLocation = Location.Y;
                    Location.Y = OldLocation.Y;

                    

                    if (Location.Y + Size.Height < i.Location.Y && Velocity.Y >= 0)
                    {
                        Velocity.Y = 0;
                        if (Location.Y + Size.Height < i.Location.Y - 1)
                            Location.Y = i.Location.Y - Size.Height - 1;
                    }
                    else if (Location.Y - Size.Height > i.Location.Y && Velocity.Y < 0)
                    {
                        
                        
                        JumpForce = 10;
                        Velocity.Y = 0;
                        
                        
                    }
                    else
                    {
                        Location.X = OldLocation.X;
                        Location.Y = saveLocation;
                        Velocity.X = 0;
                    }

                }
                else if (Velocity.X != 0)
                {
                    Location.X = OldLocation.X;
                    Velocity.X = 0;

                }
                return true;
            }
            else
                return false;
        }

        
        public void AI1()
        {
            Airborn = !OnGround();
            Random rand = new Random();
            if (Velocity.X == 0)
            {
                if (rand.Next(11) >= 6)
                    Velocity.X = 90;
                else
                    Velocity.X = -90;
            }
            if (Velocity.X < 0)
                Flip = true;
            else
                Flip = false;
        }

        public void AI2()
        {
            AI1();
           
            if (Location.X >= _gameState._world._gameItems.Hero.Location.X - 10 && Location.X <= _gameState._world._gameItems.Hero.Location.X + 10 && attackCycler <= 0)
            {
                _gameState._world._gameItems.Projectiles.Add(Generator.GenerateFireball(_gameState, (int)Location.X, (int)Location.Y + (int)Size.Height + 1));
                attackCycler = 30;
                _gameState._world._gameItems.Projectiles[_gameState._world._gameItems.Projectiles.Count - 1].JumpStart = _gameState._world._gameTime;
            }
            else
                attackCycler--;
        }

        public void AI3()
        {
            
            Random rand = new Random();
            if (Velocity.X == 0)
            {
                if (rand.Next(11) >= 6)
                    Velocity.X = 120;
                else
                    Velocity.X = -120;
            }
            if (Velocity.X < 0)
                Flip = true;
            else
                Flip = false;

            if (Velocity.Y == 0)
            {
                if (rand.Next(11) >= 6)
                    Velocity.Y = 120;
                else
                    Velocity.Y = -120;
            }
        }

        public void AI4()
        {
            if (attackCycler <= 0)
            {
                attackCycler = 40;
                ShootAcid();
            }
            else
                attackCycler--;
        }

        private void ShootAcid()
        {
            float x = 150;
            float y = 0;
            _gameState._world._gameItems.Projectiles.Add(Generator.GenerateAcid(_gameState, (int)Location.X, (int)Location.Y - 60));
            PointF l = _gameState._world._gameItems.Projectiles[_gameState._world._gameItems.Projectiles.Count - 1].Location;

            float distanceX = l.X - _gameState._world._gameItems.Hero.Location.X;
            float distanceY = l.Y - _gameState._world._gameItems.Hero.Location.Y;
            float ratio = 0;
            if (distanceX != 0)
            {
                ratio = distanceY / distanceX;



                x = distanceX * -1 / 3;
                if (x > 100)
                    x = 100;
                if (x < -100)
                    x = -100;

                y = x * ratio;
            }
            else
            {
                x = 0;
                y = 90;
            }

            _gameState._world._gameItems.Projectiles[_gameState._world._gameItems.Projectiles.Count - 1].Velocity.X = x;
            _gameState._world._gameItems.Projectiles[_gameState._world._gameItems.Projectiles.Count - 1].Velocity.Y = y;
        }

       
        public void AI5()
        {
            
        }

        public void AI6()
        {
            Random rand = new Random();
            if (Velocity.X == 0 || Velocity.X == OldVelocity.X)
            {
                OldVelocity.X = Velocity.X;
                if (rand.Next(11) >= 6)
                    Velocity.X = 1;
                else
                    Velocity.X = -1;
            }
            else if (Velocity.X > OldVelocity.X && Velocity.X > 0 && Velocity.X < 100)
            {
                OldVelocity.X = Velocity.X;
                Velocity.X += 3;
            }
            else if (Velocity.X < OldVelocity.X && Velocity.X > 0)
            {
                OldVelocity.X = Velocity.X;
                Velocity.X -= 4;
            }
            else if (Velocity.X >= 100)
            {
                OldVelocity.X = Velocity.X;
                Velocity.X -= 4;
            }
            else if (Velocity.X < OldVelocity.X && Velocity.X < 0 && Velocity.X > -100)
            {
                OldVelocity.X = Velocity.X;
                Velocity.X -= 3;
            }
            else if (Velocity.X > OldVelocity.X && Velocity.X < 0)
            {
                OldVelocity.X = Velocity.X;
                Velocity.X += 4;
            }
            else if (Velocity.X <= -100)
            {
                OldVelocity.X = Velocity.X;
                Velocity.X += 4;
            }

            if (Velocity.Y == 0 || Velocity.Y == OldVelocity.Y)
            {
                OldVelocity.Y = Velocity.Y;
                if (rand.Next(11) >= 6)
                    Velocity.Y = 1;
                else
                    Velocity.Y = -1;
            }
            else if (Velocity.Y > OldVelocity.Y && Velocity.Y > 0 && Velocity.Y < 100)
            {
                OldVelocity.Y = Velocity.Y;
                Velocity.Y += 3;
            }
            else if (Velocity.Y < OldVelocity.Y && Velocity.Y > 0)
            {
                OldVelocity.Y = Velocity.Y;
                Velocity.Y -= 4;
            }
            else if (Velocity.Y >= 100)
            {
                OldVelocity.Y = Velocity.Y;
                Velocity.Y -= 4;
            }
            else if (Velocity.Y < OldVelocity.Y && Velocity.Y < 0 && Velocity.Y > -100)
            {
                OldVelocity.Y = Velocity.Y;
                Velocity.Y -= 3;
            }
            else if (Velocity.Y > OldVelocity.Y && Velocity.Y < 0)
            {
                OldVelocity.Y = Velocity.Y;
                Velocity.Y += 4;
            }
            else if (Velocity.Y <= -100)
            {
                OldVelocity.Y = Velocity.Y;
                Velocity.Y += 4;
            }

            

           

            if (Velocity.X < 0)
                Flip = true;
            else
                Flip = false;


            if (attackCycler <= 0)
            {
                attackCycler = 18;
                ShootAcid();
            }
            else
                attackCycler--;
        }


        public void Throw(Sprite thrower)
        {
            if (!thrown)
            {
                if (thrower.Location.X < Location.X)
                {
                    Velocity.X = 100;
                }
                else
                    Velocity.X = -100;

                JumpForce = 90;
                Location.Y -= 1;
                JumpStart = _gameState._world._gameTime;
                Thrown = true;
            }
            
        }

        


    }
}
